using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;

namespace UnitTesting.Fixturing
{
	class TypedArgument : IArgument
	{
		readonly Type _type;
		readonly object _value;

		[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
		public Type Type
		{
			get { return _type; }
		}

		public object Value
		{
			get { return _value; }
		}

		internal TypedArgument(object value) : this(Ensure.IsNotNull(() => value).GetType(), value)
		{
		}

		internal TypedArgument(Type type, object value)
		{
			_type = Ensure.IsNotNull(() => type);
			_value = value;
			EnsureIsNotNullForValueType(type, value);
		}

		static void EnsureIsNotNullForValueType(Type type, object value)
		{
			if (type.IsValueType && Nullable.GetUnderlyingType(type) == null && value == null)
			{
				throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The value type '{0}' should not be null.", type));
			}
		}

		public virtual bool Equals(ParameterInfo other)
		{
			Ensure.IsNotNull(() => other);
			return other.ParameterType.IsAssignableFrom(_type);
		}

		public override string ToString()
		{
			return string.Format(CultureInfo.InvariantCulture, "Type: {0}, Value: {1}", _type, _value);
		}
	}
}